home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 2.iso
/
STUTTGART
/
TEMP
/
GNU
/
bison
/
MfcalcSymu
< prev
next >
Wrap
Text File
|
1995-06-28
|
6KB
|
220 lines
Mfcalc Symtab
Previous: <Mfcalc Rules=>MfcalcRulf> * Next: <Exercises=>Exercises> * Up: <Multi-function Calc=>Multifunct>
#Wrap on
{fH4}The {fCode}mfcalc{f} Symbol Table{f}
The multi-function calculator requires a symbol table to keep track of the
names and meanings of variables and functions. This doesn't affect the
grammar rules (except for the actions) or the Bison declarations, but it
requires some additional C functions for support.
The symbol table itself consists of a linked list of records. Its
definition, which is kept in the header {fCite}calc.h{f}, is as follows. It
provides for either functions or variables to be placed in the table.
#Wrap off
#fCode
\/\* Data type for links in the chain of symbols. \*\/
struct symrec
\{
char \*name; \/\* name of symbol \*\/
int type; \/\* type of symbol: either VAR or FNCT \*\/
union \{
double var; \/\* value of a VAR \*\/
double (\*fnctptr)(); \/\* value of a FNCT \*\/
\} value;
struct symrec \*next; \/\* link field \*\/
\};
typedef struct symrec symrec;
\/\* The symbol table: a chain of `struct symrec'. \*\/
extern symrec \*sym\_table;
symrec \*putsym ();
symrec \*getsym ();
#f
#Wrap on
The new version of {fCode}main{f} includes a call to {fCode}init\_table{f}, a
function that initializes the symbol table. Here it is, and
{fCode}init\_table{f} as well:
#Wrap off
#fCode
\#include <stdio.h>
main ()
\{
init\_table ();
yyparse ();
\}
yyerror (s) \/\* Called by yyparse on error \*\/
char \*s;
\{
printf ("%s\\n", s);
\}
struct init
\{
char \*fname;
double (\*fnct)();
\};
struct init arith\_fncts[]
= \{
"sin", sin,
"cos", cos,
"atan", atan,
"ln", log,
"exp", exp,
"sqrt", sqrt,
0, 0
\};
\/\* The symbol table: a chain of `struct symrec'. \*\/
symrec \*sym\_table = (symrec \*)0;
init\_table () \/\* puts arithmetic functions in table. \*\/
\{
int i;
symrec \*ptr;
for (i = 0; arith\_fncts[i].fname != 0; i++)
\{
ptr = putsym (arith\_fncts[i].fname, FNCT);
ptr->value.fnctptr = arith\_fncts[i].fnct;
\}
\}
#f
#Wrap on
By simply editing the initialization list and adding the necessary include
files, you can add additional functions to the calculator.
Two important functions allow look-up and installation of symbols in the
symbol table. The function {fCode}putsym{f} is passed a name and the type
({fCode}VAR{f} or {fCode}FNCT{f}) of the object to be installed. The object is
linked to the front of the list, and a pointer to the object is returned.
The function {fCode}getsym{f} is passed the name of the symbol to look up. If
found, a pointer to that symbol is returned; otherwise zero is returned.
#Wrap off
#fCode
symrec \*
putsym (sym\_name,sym\_type)
char \*sym\_name;
int sym\_type;
\{
symrec \*ptr;
ptr = (symrec \*) malloc (sizeof (symrec));
ptr->name = (char \*) malloc (strlen (sym\_name) + 1);
strcpy (ptr->name,sym\_name);
ptr->type = sym\_type;
ptr->value.var = 0; \/\* set value to 0 even if fctn. \*\/
ptr->next = (struct symrec \*)sym\_table;
sym\_table = ptr;
return ptr;
\}
symrec \*
getsym (sym\_name)
char \*sym\_name;
\{
symrec \*ptr;
for (ptr = sym\_table; ptr != (symrec \*) 0;
ptr = (symrec \*)ptr->next)
if (strcmp (ptr->name,sym\_name) == 0)
return ptr;
return 0;
\}
#f
#Wrap on
The function {fCode}yylex{f} must now recognize variables, numeric values, and
the single-character arithmetic operators. Strings of alphanumeric
characters with a leading nondigit are recognized as either variables or
functions depending on what the symbol table says about them.
The string is passed to {fCode}getsym{f} for look up in the symbol table. If
the name appears in the table, a pointer to its location and its type
({fCode}VAR{f} or {fCode}FNCT{f}) is returned to {fCode}yyparse{f}. If it is not
already in the table, then it is installed as a {fCode}VAR{f} using
{fCode}putsym{f}. Again, a pointer and its type (which must be {fCode}VAR{f}) is
returned to {fCode}yyparse{f}.
No change is needed in the handling of numeric values and arithmetic
operators in {fCode}yylex{f}.
#Wrap off
#fCode
\#include <ctype.h>
yylex ()
\{
int c;
\/\* Ignore whitespace, get first nonwhite character. \*\/
while ((c = getchar ()) == ' ' || c == '\\t');
if (c == EOF)
return 0;
\/\* Char starts a number => parse the number. \*\/
if (c == '.' || isdigit (c))
\{
ungetc (c, stdin);
scanf ("%lf", &yylval.val);
return NUM;
\}
\/\* Char starts an identifier => read the name. \*\/
if (isalpha (c))
\{
symrec \*s;
static char \*symbuf = 0;
static int length = 0;
int i;
\/\* Initially make the buffer long enough
for a 40-character symbol name. \*\/
if (length == 0)
length = 40, symbuf = (char \*)malloc (length + 1);
i = 0;
do
\{
\/\* If buffer is full, make it bigger. \*\/
if (i == length)
\{
length \*= 2;
symbuf = (char \*)realloc (symbuf, length + 1);
\}
\/\* Add this character to the buffer. \*\/
symbuf[i++] = c;
\/\* Get another character. \*\/
c = getchar ();
\}
while (c != EOF && isalnum (c));
ungetc (c, stdin);
symbuf[i] = '\\0';
s = getsym (symbuf);
if (s == 0)
s = putsym (symbuf, VAR);
yylval.tptr = s;
return s->type;
\}
\/\* Any other character is a token by itself. \*\/
return c;
\}
#f
#Wrap on
This program is both powerful and flexible. You may easily add new
functions, and it is a simple job to modify this code to install predefined
variables such as {fCode}pi{f} or {fCode}e{f} as well.